/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Portions created by the Initial Developer are
 * Copyright (C) 2012 the Initial Developer.
 * All Rights Reserved.
 *
 * The Original Code is "http://semi-frame.googlecode.com/svn/trenk/".
 *
 * The Initial Developer of the Original Code is the author below.
 */

/**
 * @file Logger.cpp
 * @brief auto generated.
 * @author morningcloud
 * @date 2011/03/11
 */

#include "semi/logg/Logger.h"

namespace semi {
namespace logg {

Logger::LoggerMap Logger::loggerPool;
Logger Logger::current;

int Logger::LV_TRACE = 1;
int Logger::LV_DEBUG = 2;
int Logger::LV_INFO = 3;
int Logger::LV_WARN = 4;
int Logger::LV_ERROR = 5;
int Logger::LV_FATAL = 6;

Logger::Logger() {
	this->loglevel = 0;
}

Logger::~Logger() {
}

Logger Logger::getCurrentLogger() {

	if (0 == Logger::current.loglevel)
		Logger::current = Logger::getLogger("DEFAULT");

	return Logger::current;
}

Logger Logger::addLogger(std::string logname, Logger loggr) {

	Logger newLgr;
	newLgr.Name = logname;
	newLgr.loglevel = loggr.loglevel;
	newLgr.confName = loggr.confName;
	newLgr.printer = loggr.printer; // divert
	loggerPool[logname] = newLgr;

	return newLgr;
}

// static
Logger Logger::getLogger(std::string logname) {

	// fit all
	if (0 < loggerPool.count(logname)) {
		// std::cout << "fit " << logname << " count:"<< indexMap.count(logname) << std::endl;
		// std::cout << logname << ":" << indexMap[logname] << std::endl;
		Logger::current = loggerPool[logname];
		return Logger::current;
	}

	// fit fore
	for (Logger::LoggerMap::iterator iter = loggerPool.begin(); iter
			!= loggerPool.end(); iter++) {

		// std::string exists = (std::string) iter->first; // exists log name AAA. etc
		Logger oldLgr = (Logger) iter->second; // Logger
		std::string conf = oldLgr.confName;

		if (0 == strncmp(conf.c_str(), logname.c_str(), conf.length())) {
			//            std::cout << "    LoggerPool::getLogger fit configure " << logname
			//                    << " conf:" << conf << std::endl;
			Logger oldLgr = (Logger) iter->second; // Logger
			Logger::current = Logger::addLogger(logname, oldLgr);
			return Logger::current;
		}
	}

	// make new logger
	Logger ret;
	semi::conf::Configurator::LogConfig conf =
			semi::conf::Configurator().getLogConfig(logname);
	if (0 == conf.log_name || 0 == conf.log_name[0]) {
		std::cout << "    Logger::getLogger LogConfig is empty!" << std::endl;
		return ret;
	}

	ret.confName = conf.log_name;
	ret.Name = logname;
	ret.configureLevel(conf.log_level);

	// parameter
	if (0 < conf.log_size)
		ret.printer.init(conf.log_path, conf.log_size);
	else
		ret.printer.init(conf.log_path);

	std::cout << "    Logger::getLogger New logger created! name:"
			<< ret.confName << "(" << logname << ") " << conf.log_level
			<< " printer:" << conf.log_path << std::endl;

	loggerPool[logname] = ret;
	Logger::current = ret;
	return Logger::current;
}

void Logger::configureLevel(std::string strLevel) {

	// FATAL output minimum
	if (strLevel == LV_NM_FATAL && loglevel < LV_FATAL) {
		loglevel = LV_FATAL; // Level = "FATAL";
	}
	// ERROR
	if (strLevel == LV_NM_ERROR && loglevel < LV_ERROR) {
		loglevel = LV_ERROR; // Level = "ERROR";
	}
	// WARN
	else if (strLevel == LV_NM_WARN && loglevel < LV_WARN) {
		loglevel = LV_WARN; // Level = "WARN";
	}
	// INFO
	else if (strLevel == LV_NM_INFO && loglevel < LV_INFO) {
		loglevel = LV_INFO; // Level = "INFO";
	}
	// DEBUG
	else if (strLevel == LV_NM_DEBUG && loglevel < LV_DEBUG) {
		loglevel = LV_DEBUG; // Level = "DEBUG";
	}
	// TRACE output maximum
	else if (strLevel == LV_NM_TRACE && loglevel < LV_TRACE) {
		loglevel = LV_TRACE; // Level = "TRACE";
	} else {
		// 0:�Ǿ����ϥ�٥��
		;
	}
	// std::cout << "loglevel:" << loglevel << std::endl;
}

bool Logger::isWarnEnabled() {
	return loglevel <= LV_WARN;
}

bool Logger::isInfoEnabled() {
	return loglevel <= LV_INFO;
}

bool Logger::isDebugEnabled() {
	return loglevel <= LV_DEBUG;
}

bool Logger::isTraceEnabled() {
	return loglevel <= LV_TRACE;
}

void Logger::trace(std::string msg, std::string func, std::string file,
		int line) {
	if (isTraceEnabled())
		printer.logging("%5s %10s %s \n", LV_NM_TRACE.c_str(), Name.c_str(),
				util::LogUtil::createMessage(msg, func, file, line).c_str());
}

void Logger::debug(std::string msg, std::string func, std::string file,
		int line) {
	if (isDebugEnabled())
		printer.logging("%5s %10s %s \n", LV_NM_DEBUG.c_str(), Name.c_str(),
				util::LogUtil::createMessage(msg, func, file, line).c_str());
}

void Logger::info(std::string msg, std::string func, std::string file, int line) {
	if (isInfoEnabled())
		printer.logging("%5s %10s %s \n", LV_NM_INFO.c_str(), Name.c_str(),
				util::LogUtil::createMessage(msg, func, file, line).c_str());
}

void Logger::warn(std::string msg, std::string func, std::string file, int line) {

	if (!isWarnEnabled())
		return;

	std::stringstream ss;

	ss << util::LogUtil::createMessage(msg, func, file, line);
	// ss << " \n\t\t";

	void *bks[128];
	char **trc;
	int n = backtrace(bks, sizeof(bks) / sizeof(bks[0]));
	trc = backtrace_symbols(bks, n);
	//    if (1 < n)
	//        ss << trc[1];
	for (int i = 1; 1 < n && i < n && i < 3; i++) {
		ss << "\n\t\t";
		ss << trc[i];
	}

	free(trc);

	printer.logging("%5s %10s %s \n", LV_NM_WARN.c_str(), Name.c_str(),
			ss.str().c_str());
}

void Logger::error(std::string msg, std::string func, std::string file,
		int line) {

	if (LV_ERROR < loglevel)
		return;

	std::stringstream ss;

	ss << util::LogUtil::createMessage(msg, func, file, line);
	void *bks[128];
	char **trc;
	int n = backtrace(bks, sizeof(bks) / sizeof(bks[0]));
	trc = backtrace_symbols(bks, n);
	for (int i = 0; i < n; i++) {
		ss << "\n\t\t";
		//        ss << i;
		//        ss << ":";
		ss << trc[i];
	}
	free(trc);

	printer.logging("%5s %10s %s \n", LV_NM_ERROR.c_str(), Name.c_str(),
			ss.str().c_str());
}

void Logger::fatal(std::string msg, std::string func, std::string file,
		int line) {

	std::stringstream ss;

	ss << util::LogUtil::createMessage(msg, func, file, line);
	void *bks[128];
	char **trc;
	int n = backtrace(bks, sizeof(bks) / sizeof(bks[0]));
	trc = backtrace_symbols(bks, n);
	for (int i = 0; i < n; i++) {
		ss << "\n\t\t";
		//        ss << i;
		//        ss << ":";
		ss << trc[i];
	}
	free(trc);

	printer.logging("%5s %10s %s \n", LV_NM_FATAL.c_str(), Name.c_str(),
			ss.str().c_str());
}

bool Logger::releaseLock() {

	// ��å�����
	semi::posix::Semaphore sem(this->printer.file_path);
	sem.terminate();
	return true;
}

// static
void Logger::releaseLockAll() {
	//    for (Logger::LoggerMap::iterator iter = loggerPool.begin(); iter
	//            != loggerPool.end(); iter++) {
	//        Logger lgr = (Logger) iter->second; // Logger
	//        if (0 == &lgr.confName || 0 == lgr.confName.length())
	//            continue;
	//        lgr.printer.terminate();
	//    }
	conf::Configurator::LogConfigs lcnf = conf::Configurator::getLogConfigs();
	for (int idx = 0; idx < (sizeof(conf::Configurator::LogConfigs)
			/ sizeof(conf::Configurator::LogConfig)); idx++) {
		conf::Configurator::LogConfig cnf = lcnf.logConfig[idx];
		std::string pth = std::string(cnf.log_path);
		if (0 == pth.length())
			continue;
		semi::posix::Semaphore sem(pth);
		sem.terminate();
	}

}

std::string Logger::toString() {

	std::stringstream ss;
	ss << "Logger::toString name:" << this->Name << " level:" << this->loglevel
			<< " path:" << this->printer.file_path << std::endl;
	return ss.str();
}

// static
std::string Logger::toStringAll() {

	std::stringstream ss;
	ss << "Logger logger pool" << std::endl;
	for (Logger::LoggerMap::iterator iter = loggerPool.begin(); iter
			!= loggerPool.end(); iter++) {
		Logger lgr = (Logger) iter->second; // Logger
		if (0 == &lgr.confName || 0 == lgr.confName.length())
			continue;
		ss << "    " << lgr.toString();
	}
	return ss.str();
}

}
}
